package com.gillion.grule.client.core;

import com.gillion.grule.client.core.variable.AssemblyVariable;
import com.gillion.grule.client.core.variable.DecisionTreeVariable;
import com.gillion.grule.client.core.variable.DecisionVariable;
import com.gillion.grule.client.core.variable.PackageVariable;
import com.gillion.grule.client.core.variable.RuleVariable;
import com.gillion.grule.client.logger.LoggerAppenderHolder;
import com.gillion.grule.client.utils.RuleDateUtils;
import com.gillion.grule.client.utils.TempletUtil;
import com.gillion.grule.client.utils.Tools;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import lombok.Data;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.map.HashedMap;
import org.mvel2.MVEL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Data
public class Context
{

    private static final Logger log = LoggerFactory.getLogger(Context.class);
    private List<Object> params = Lists.newArrayList();
    private Object rtnValue;
    private BusinessModel businessModel;
    private PackageVariable packageVariable;
    private boolean breakPackage = false;
    private Map<String, Boolean> breakAssemblys = Maps.newConcurrentMap();
    private List<DataSourceClient> dataSources = Lists.newArrayList();
    private List<RemoteConfig> remoteConfig = Lists.newArrayList();
    private List<SpringCloudConfig> springCloudConfig = Lists.newArrayList();
    private List<GroovyShellConfig> groovyShellConfigs = Lists.newArrayList();
    private List<DubboConfig> dubboConfig = Lists.newArrayList();
    private Map<String, Map<String, Object>> validatorConfig = Maps.newConcurrentMap();
    public Object param(String expression) {
        return MVEL.eval(expression, this);
    }
    public Boolean isBreakAssembly(String name) {
        return MapUtils.getBoolean(this.breakAssemblys, name, Boolean.valueOf(false));
    }





    public Boolean isBreakPackage() {
        return Boolean.valueOf(this.breakPackage);
    }





    public void breakAssembly(String name) {
        this.breakAssemblys.put(name, Boolean.valueOf(true));
    }




    public void breakPackage() {
        this.breakPackage = true;
    }






    public void setRtnValue(String rtnExpression) {
        Map<String, Object> context = Maps.newConcurrentMap();
        context.put("$context", this);
        context.put("$model", this.businessModel);
        context.put("RuleDateUtils", RuleDateUtils.class);
        context.put("Tools", Tools.class);
        context.put("TempletUtil", TempletUtil.class);

        context.put("$variable", this);
        this.rtnValue = MVEL.eval(rtnExpression, context);
    }

    public void setRealRtnValue(Object rtnValue) {
        this.rtnValue = rtnValue;
    }







    public void log(String message, Object... args) {
        LoggerAppenderHolder.log(message, args);
    }




    public String toString() { return "Context(params=" + getParams() + ", rtnValue=" + getRtnValue() + ", businessModel=" + getBusinessModel() + ", packageVariable=" + getPackageVariable() + ", breakPackage=" + isBreakPackage() + ", breakAssemblys=" + getBreakAssemblys() + ", dataSources=" + getDataSources() + ", remoteConfig=" + getRemoteConfig() + ", springCloudConfig=" + getSpringCloudConfig() + ", groovyShellConfigs=" + getGroovyShellConfigs() + ", dubboConfig=" + getDubboConfig() + ", validatorConfig=" + getValidatorConfig() + ")"; }
    public void setBreakPackage(boolean breakPackage) {
        this.breakPackage = breakPackage;
    }


    public AssemblyVariable getAssemblyVariable(String assemblyName) {
        return (AssemblyVariable)getPackageVariable().getAssemblyVariables().get(assemblyName);
    }

    public AssemblyVariable getAssemblyVariable() {
        AssemblyVariable variable = new AssemblyVariable();
        HashedMap hashedMap = new HashedMap();
        Map<String, AssemblyVariable> assemblyVariableMap = getPackageVariable().getAssemblyVariables();

        for (String assemblyName : assemblyVariableMap.keySet()) {
            hashedMap.putAll(((AssemblyVariable)assemblyVariableMap.get(assemblyName)).getVariables());
        }
        variable.setVariables((Map)hashedMap);
        variable.setPackageVariable(getPackageVariable());
        return variable;
    }







    public RuleVariable getRuleVariable(String assemblyName, String ruleName) {
        return (RuleVariable)((AssemblyVariable)getPackageVariable().getAssemblyVariables().get(assemblyName)).getRuleVariables().get(ruleName);
    }






    public DecisionVariable getDecisionVariable(String decisionName) {
        return (DecisionVariable)getPackageVariable().getDecisionVariables().get(decisionName);
    }






    public DecisionTreeVariable getDecisionTreeVariable(String decisionName) {
        return (DecisionTreeVariable)getPackageVariable().getDecisionTreeVariables().get(decisionName);
    }





    public Object variable(String variableName) {
        Object value = getPackageVariable().getVariable(variableName);
        if (value == null) {
            Map<String, AssemblyVariable> assemblyVariableMap = getPackageVariable().getAssemblyVariables();
            for (String key : assemblyVariableMap.keySet()) {
                value = ((AssemblyVariable)assemblyVariableMap.get(key)).getVariables().get(variableName);
                if (value == null) {
                    Map<String, RuleVariable> ruleVariables = ((AssemblyVariable)assemblyVariableMap.get(key)).getRuleVariables();
                    Iterator<String> iterator = ruleVariables.keySet().iterator(); if (iterator.hasNext()) { String ruleKey = iterator.next();
                        value = ((RuleVariable)ruleVariables.get(ruleKey)).getVariables().get(variableName); }

                }
            }
        }



        return value;
    }


    public Object getVariable(String variableName) {
        return variable(variableName);
    }



    public void setVariable(String key, Object value) {
        if (value instanceof Integer) {
            value = new BigDecimal(((Integer)value).intValue());
        }
        this.packageVariable.setVariables(key, value);
    }

    public static void main(String[] args) {}
}